﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reactive.Threading.Tasks;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
using System.Xaml;

using alib;
using alib.Debugging;
using alib.Enumerable;
using alib.String;

using agree.schema;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public enum ItemStatus
	{
		Unknown = 0,
		Grammatical = 1,
		Malconstrued = 2,
		Malcoherent = 3,
		Ungrammatical = 4,
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ItemsList : IdentList<IString>
	{
		public ItemsList(IIdentity prv)
			: base(prv)
		{
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class Item : StringItem, IItem
	{
		[DebuggerStepThrough]
		public Item(IIdentity prv, String s)
			: base(prv, s)
		{
			this.ItemIndex = -1;
			this.ItemStatus = ItemStatus.Grammatical;
		}
		[DebuggerStepThrough]
		public Item(IIdentity prv)
			: this(prv, default(String))
		{
		}

		[DebuggerStepThrough]
		public Item(String s)
			: this(default(IIdentity), s)
		{
		}

		ItemStatus _status;
		public ItemStatus ItemStatus
		{
			get { return _status; }
			set { _status = value; }
		}

		String _ref;
		public String Reference
		{
			get { return _ref ?? ""; }
			set { _ref = value; }
		}

		String _notes;
		public String Notes
		{
			get { return _notes ?? ""; }
			set { _notes = value; }
		}

		public String SourceId { get; set; }

		int c_expected_derivations;
		public int ExpectedDerivationCount
		{
			get { return c_expected_derivations; }
			set { c_expected_derivations = value; }
		}

		public IString Translation
		{
			get
			{
				if (translations == null)
					return StringItem.Empty;
				var arr = translations.GetTrimmed();
				if (arr.Length == 1)
					return arr[0];
				return new StringItem(this, translations.Select(_s => _s.Text).StringJoin("; "));
			}
			set
			{
				var arr = value.Text.Split(';');
				if (arr.Length == 1)
					Translations.Add(value);
				else
					Translations.AddRange(arr.Select(_s => new StringItem(_s.Trim())));
			}
		}

		ItemsList translations;
		public ItemsList Translations
		{
			get
			{
				if (translations == null)
					translations = new ItemsList(this);
				return translations;
			}
			set
			{
				if (value == translations)
					return;
				if (value == null)
					translations = null;
				else if (translations == null)
					translations = value;
				else
					translations.AddRange(value);
			}
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class UseTranslation : composition.f_primitive<IString, IString>
	{
		public UseTranslation(IRtParent parent)
			: base(parent)
		{
		}
		protected override IString func(IString item)
		{
			IString x;
			if ((x = (IString)P.Translation.GetValue(item)) != null && !String.IsNullOrEmpty(x.Text))
				item = x;
			return item;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class EnabledItems : m_scalar_base<IIdentList<IString>, IIdentList<IString>>
	{
		public EnabledItems(IRtParent parent, IIdentList<IString> items)
			: base(parent, items)
		{
		}

		protected override IIdentList<IString> start(IIdentList<IString> items)
		{
			var arr = new IString[items.Count];
			int i = 0;
			IString item;
			StringItem si;
			for (int j = 0; j < arr.Length; j++)
				if ((si = (item = items[j]) as StringItem) == null || si.ItemEnable)
					arr[i++] = item;

			alib.Array.arr.Resize(ref arr, i);
			return new IdentArray<IString>(items, arr);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class EnabledItems2 : m_observable<IIdentList<IString>, IString>
	{
		public EnabledItems2(IRtParent parent, IIdentList<IString> items)
			: base(parent, items)
		{
		}

		protected override void start(IIdentList<IString> items)
		{
			IString item;
			StringItem si;
			for (int j = 0; j < items.Count; j++)
				if ((si = (item = items[j]) as StringItem) == null || si.ItemEnable)
					_item(item);

			_remove_task();
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public class SourceWord : StringItem, IEquatable<SourceWord>, ISourceWord, ρρPosProbs
	{
		public SourceWord(IIdentity prv, String s)
			: base(prv, s)
		{
		}
		public SourceWord(IIdentity prv, String s, String source_text, int i_from, int i_to)
			: this(prv, s)
		{
			this.i_from = i_from;
			this.i_to = i_to;
		}
		public SourceWord(IIdentity prv)
			: this(prv, default(String))
		{
		}


		///////////////////////////////////////////////////////////////////////
		///
		int i_from;
		public int SourceCharacterStart
		{
			get { return i_from; }
			set { i_from = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		///
		int i_to;
		public int SourceCharacterEnd
		{
			get { return i_to; }
			set { i_to = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		///
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String SurfaceForm
		{
			get { return base.Text; }
			set { base.Text = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		///
		public bool HasPosTags { get { return pos_probs != null; } }
		alib.Hmm.PosProb[] pos_probs;
		public alib.Hmm.PosProb[] PosProbs
		{
			get { return pos_probs ?? alib.Collections.Collection<alib.Hmm.PosProb>.None; }
			set
			{
				if (value == null)
					return;
				if (value.Length == 0)
					value = null;
				pos_probs = value;
			}
		}
		///
		///////////////////////////////////////////////////////////////////////


		public bool Equals(SourceWord other)
		{
			return base.Equals((StringItem)other) &&
				this.i_from == other.i_from && this.i_to == other.i_to &&
				this.pos_probs.SequenceEqual(other.pos_probs);
		}
		public override bool Equals(object o)
		{
			return o is SourceWord && this.Equals((SourceWord)o);
		}
		public override int GetHashCode()
		{
			return base.GetHashCode() ^ (i_from << 16) ^ i_to;
		}
		public override String ToString()
		{
			return String.Format("{0,10} [{1} {2}]", base.ToString(), i_from, i_to);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public class WordToken : SourceWord, IWordToken
	{
		public WordToken(IIdentity prv, String s)
			: base(prv, s)
		{
		}
		public WordToken(IIdentity prv, String s, int i_from, int i_to, int i_tok)
			: base(prv, s, s, i_from, i_to)
		{
			this.tok_span = new ChartSpan(i_tok, i_tok);
		}

		///////////////////////////////////////////////////////////////////////
		///
		ChartSpan tok_span;
		public ChartSpan TokenSpan
		{
			get { return this.tok_span; }
			set { this.tok_span = value; }
		}
		///
		///////////////////////////////////////////////////////////////////////
	};
}